#define _GNU_SOURCE
#include "app_serial.h"
#include "log/log.h"

//初始化:设置波特率、校验位、停止位、是否阻塞、是否原始模式
int app_serial_init(Device * device){
    app_serial_setBraudRate(device,BR_9600);
    app_serial_setParity(device,Parity_NONE);
    app_serial_setStopBits(device,SB_1);
    app_serial_setRaw(device);
    //app_serial_setBlock(device,1); //刚开始不阻塞

    //刷新后才能生效
    int result= tcflush(device->fd,TCIOFLUSH); //刷新
    if(result!=0){
        log_error("初始化串口失败");
        return -1;
    }
    log_debug("初始化串口成功");
    return 0;
}

//设置波特率
int app_serial_setBraudRate(Device * device, BraudRate baudRate){
    struct termios attr;
    //获取属性
    tcgetattr(device->fd,&attr);
    //设置输入输出波特率（可以分开设置）
    cfsetspeed(&attr,baudRate);
    //设置属性（刷新后生效，NOW是立马生效）
    int result= tcsetattr(device->fd,TCSAFLUSH,&attr);
    if(result!=0){
        log_error("设置串口波特率失败");
        return -1;
    }
    log_debug("设置串口波特率成功");
    return 0;
}

//设置校验位
int app_serial_setParity(Device * device, Parity parity){
    struct termios attr;
    //获取属性
    tcgetattr(device->fd,&attr);
    //设置校验位
    attr.c_cflag &= ~(PARENB|PARODD); //清除校验位
    attr.c_cflag |= parity;
    //设置属性（刷新后生效，NOW是立马生效）
    int result= tcsetattr(device->fd,TCSAFLUSH,&attr);
    if(result!=0){
        log_error("设置串口校验位失败");
        return -1;
    }
    log_debug("设置串口校验位成功");
    return 0;
}

//设置停止位
int app_serial_setStopBits(Device * device, StopBits stopBits){
    struct termios attr;
    //获取属性
    tcgetattr(device->fd,&attr);
    //设置停止位
    attr.c_cflag &= ~CSTOPB; //清除停止位
    attr.c_cflag |= stopBits;
    //设置属性（刷新后生效，NOW是立马生效）
    int result= tcsetattr(device->fd,TCSAFLUSH,&attr);
    if(result!=0){
        log_error("设置串口停止位失败");
        return -1;
    }
    log_debug("设置串口停止位成功");
    return 0;
}

//设置串口是否是阻塞模式(0:非阻塞，1:阻塞)
int app_serial_setBlock(Device * device,int block){
    struct termios attr;
    //获取属性
    tcgetattr(device->fd,&attr);
    //设置阻塞模式
    if(block==0){
        attr.c_cc[VMIN]=0;   //字符读取0
        attr.c_cc[VTIME]=2;  //读取时间200ms
    }else{
        attr.c_cc[VMIN]=1;   //字符读取到1个再返回
        attr.c_cc[VTIME]=0;
    }
    //设置属性（刷新后生效，NOW是立马生效）
    int result= tcsetattr(device->fd,TCSAFLUSH,&attr);
    if(result!=0){
        log_error("设置串口阻塞模式失败");
        return -1;
    }
    log_debug("设置串口阻塞模式成功");
    return 0;
}

//设置串口解析数据模式为原始模式：不解析特殊字符
int app_serial_setRaw(Device * device){
    struct termios attr;
    //获取属性
    tcgetattr(device->fd,&attr);
    //设置原始模式(要扩展#define _GNU_SOURCE)
    cfmakeraw(&attr); //清除所有标志位
    //设置属性（刷新后生效，NOW是立马生效）
    int result= tcsetattr(device->fd,TCSAFLUSH,&attr);
    if(result!=0){
        log_error("设置串口原始模式失败");
        return -1;
    }
    log_debug("设置串口原始模式成功");
    return 0;
}
